#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define RADIAN 57.295776

#define IS_DONO 1
#define IS_ACCE 2
#define IS_CA 4
#define IS_CB 8
#define IS_BACKBONE 16
#define IS_MAINCHAIN_AND_CB 32
#define IS_LOCAL_AA 64

#define R_MAX 1.9
#define PACKING_CUTOFF 7.0
#define K_OVERLAP 10.0

int mode; /* 0: all 1: mainchain+cb */
//int packing; /* 0:without packing energy 1: with packing energy */
int loop_length;

struct atomname {
	char resname[4];
	char atomname[4];
};

/* data structure for sidechain rotamer */
struct sidechain {
	int atom_num, angle_num, rotamer_num;
	struct atomname atom[13];
	struct rotamer {
		float coor[13][3];
		float angle[4];
		float deal[13][3];
	} *rotamer;
} sidechain[20];

/* data strucuture for environatom */
#define ATOMNUM 8000
struct environatom {
	float coor[3], radius;
	int resno, type;
	unsigned char status;
	struct atomname name;
} environatom[ATOMNUM];
int atomnum;

/* data structure for loop */
#define LOOPNUM 600
#define LOOPRES 40
#define MAX_SEGMENT 5

int table[LOOPNUM][LOOPNUM]; /* 1: fixed distance 2: 1-4 0: free */

struct anchor {
	float N[3], CA[3];
};

struct loop {
	struct loopatom {
		float radius, scale_factor;
		unsigned char status;
		int resno, type, build_flag;
		struct atomname name;
	} loopatom[LOOPNUM];
	int loopnum, resnum, resnum2, resno[LOOPRES], circle;
	int start[LOOPRES], end[LOOPRES], type[LOOPRES], seg_start[MAX_SEGMENT], seg_end[MAX_SEGMENT], nseg;
	struct anchor anchor[MAX_SEGMENT];
	double probility;
} loop;

struct candidate {
	float coor[LOOPNUM][3];
	int rotamer[LOOPRES];
	float phi[LOOPRES], psi[LOOPRES];
	struct anchor dummy_anchor[MAX_SEGMENT];
	float energy, energy1, energy2, energypmf, energyavg2;
	int packing;
} current[2], ref, *candidate, *candidate2;

/* nsaves: number of saved loop structure in current stage
 * nsaves2: number of saved loop structure in previous stage
 * repr_num[i]: the number of members of the cluster i */
int nsaves, nsaves2, *repr_num;

long int numofsamples;

#define CLUSTER_THRESHOLD 50

#define START 2
#define END 12
#define CONTACT_CUTOFF 7.0
struct pmfscore {
	float energy[20][20];
	float energysol[20][END - START + 1];
} pmfscore;

/* build.c */
extern void paste_sidechain(float [3], float [3], float [3], struct candidate *, int, int, int, int, int);
extern void build_loops(char *, int, char [5][20], int *, int *);
extern void read_environatom(char *, int, int *, int *);

/* closure.c */
extern int loop_closure2(struct candidate *, int, int, int);

/* cluster.c */
extern int loop_cluster(float);

/* energy.c */
extern int calc_energy1(struct candidate *);
extern float calc_energy2(struct candidate *, int);

/* pmfscore.c */
extern void read_pmfscore (void);
extern void calc_pmfscore (struct candidate *);

/* grid.c */
extern void grid_mapping(void);
extern void grid2_mapping(void);

/* mmc.c */
extern int mmc(int, float);

/* randomwalk.c */
extern void randomwalk(int, float);

/* ramachandran.c */
extern void init_Ramachandran_plot(void);
extern float normal_angle(float);
extern float allow_angle(float, float, int, int, float);
extern int judge_phi_psi(float, float, int);
extern void rand_phi_psi(float *, float *, int);
extern void rand_phi_psi2(float *, float *, float, float, int, float);

/* table.c */
extern void build_table(void);

/* utils.c */
extern float judge_radius(struct atomname);
extern unsigned char judge_status(struct atomname);
extern void matrix_inverse(float [3*3], float [3*3]);
extern void linear_solve(float [3*3], float [3], float [3]);
extern void rotate_matrix(float [3], float [3], float, float [3*3]);
extern void rotate_atom(float [3], float [3], float [3], float);
extern void rotate_atoms(float [3], float [3], struct candidate *, int, int [600], float);
extern void set_flag(int, int, int, int [600]);
extern int random_rotate(struct candidate *, int);
extern int random_rotate2(struct candidate *, int, float);
extern void reinit(struct candidate *);
extern void purturb_mainchain();
extern void purturb_sidechain();
extern float calc_rmsd(struct candidate *, struct candidate *);
extern void loop_output(char *);
